const Router = require('koa-router');
const router = new Router();
const {db, QueryTypes, Op} = require('../models/db')
const tool = require("../tools/tool");
const {updateInventoryByBill, insertInventory} = require("./base")
// 检测库存
const detectStock = async (ctx) => {
    let body = ctx.request.body
    let tid = ctx.user.tenantId
    let transType = ctx.request.body.transType
    // if ([150601,150602,150603,150501,150502,150706,150806].indexOf(transType) !== -1 ) {
    //     let infos = body.invoiceInfos
    //     if(!infos || infos.length === 0) throw Error('没有明细数据')
    //     let arr = []
    //     infos.map(row => {
    //         if(row.invId) {
    //             let qty = row.qty
    //             if(transType === 150501) qty = -qty
    //             if(transType === 150706) qty = -qty
    //             if(transType === 150603) if(row.trans === '换入')  qty = -qty
    //             let str = `select ${tid} tenantId, ${row.locationId} locationId, ${row.invId} invId, ${qty} qty `
    //             arr.push(str)
    //         }
    //     })
    //     if(arr.length === 0) throw Error('没有明细数据')
    //     let sumSql = `select tenantId,locationId,invId,sum(qty) qty from (${arr.join(' union all ')}) a group by tenantId, locationId, invId`
    //     let sql = `select a.tenantId,a.locationId,a.invId,g.name invName,g.spec,g.unit1,a.qty,isnull(b.balanceCount,0) leftC from (${sumSql}) a
    //                 inner join goods g on a.invId=g.id left join inventory b on a.tenantId=b.tenantId and a.locationId=b.locationId and a.invId=b.invId
    //                  where a.qty > isnull(b.balanceCount, 0)`
    //     let list = await db.query(sql, {type: QueryTypes.SELECT})
    //     if(list.length > 0) {
    //         let left = tool.xe.round(tool.Np.divide(list[0].qty,list[0].spec) , 2)
    //         throw Error(`【${list[0].invName}】 库存不足,结余【${left}】${list[0].unit1}`)
    //     }
    // }
}
const setBillNo = async (ctx) => {
    let tenantId = ctx.user.tenantId;
    let transType = tool.xe.toNumber(ctx.request.body.transType)
    let billDate = tool.getDay()
    if (!transType) throw Error('未传入票据类型')
    let bd = tool.getDay('',0,'DAY','YYYYMMDD')
    let prefix = '';
    if (transType === 150501) {
        prefix = 'CG'; // 采购
    }
    if (transType == 150502) {
        prefix = 'CT'; // 采退
    }
    if (transType == 150601) {
        prefix = 'XS'; // 销售
    }
    if (transType == 150602) {
        prefix = 'XT'; // 销退
    }
    if (transType == 150603) {
        prefix = 'XH'; // 换货
    }
    if (transType == 150706) {
        prefix = 'QTRK'; // 其它入库
    }
    if (transType == 150806) {
        prefix = 'QTCK'; // 其它出库
    }
    if (transType == 153001) {
        prefix = 'SK'; // 收款
    }
    if (transType == 153401) {
        prefix = 'SR'; // 收入
    }
    if (transType == 153101) {
        prefix = 'FK'; // 付款
    }
    if (transType == 153402) {
        prefix = 'ZC'; // 支出
    }
    if (transType == 153403) {
        prefix = 'YSG';
    }
    if (transType == 153407) {
        prefix = 'YSK'; // 预收钱  不关联商品
    }
    if (transType == 153404) {
        prefix = 'YS'; //应收款
    }
    if (transType == 153405) {
        prefix = 'YF'; // 应付
    }
    if (transType == 153406) {
        prefix = 'YFK'; // 员工支出
    }
    if (transType == 160001) {
        prefix = 'ZZ'; // 银行转账
    }
    if (transType == 190001) {
        prefix = 'PZ'; // 凭证
    }
    if (transType == 180001) {
        prefix = 'PD'; // 派单收款
    }
    if (!prefix) {
        throw Error('票号生成失败')
    }
    try {
        let no = await db.models['invoice'].count({
            where: {
                tenantId,
                transType,
                billDate
            }
        })
        return  prefix + bd + '-' + (no + 1);

    } catch (e) {
        throw Error('票号生成失败')
    }
}
const assamblePrint = async ( print_at, invoice, tenantName, descript, ctx) => {
    let sql = `select a.*,b.name doName,c.name cbyName,d.name salesName,ca.name accName,ca1.name accName1 from (
                                 select b.name buName,b.linkMobile,b.address,a.cby,a.doId,a.salesId,a.accId,a.accId1 from invoice a inner join contact b on a.buId=b.id  where a.id=${invoice.id}
    ) a left join admin b on a.doId=b.id left join admin c on a.cby=c.id left join admin d on a.salesId=d.id
        left join category ca on a.accId=ca.id
        left join category ca1 on a.accId1=ca1.id
    `
    let vInvoice = await db.query(sql, {
        type: QueryTypes.SELECT, plain: true
    })
    try {
        let strs = []
        let title = printTitle(invoice, tenantName, print_at, ctx);
        let headInfo = printHeadInfo(invoice, vInvoice, ctx);
        let headtable = printTableHead(invoice, ctx);
        let bodyTable = await printTable(invoice, vInvoice, ctx);
        let foot = printTfoot(invoice,vInvoice, descript, ctx);
        strs.push(title.data);
        strs.push(headInfo.data);
        strs.push(headtable.data);
        strs.push(bodyTable.data);
        strs.push(foot.data);
        return ctx.suc('',strs.join(''))
    } catch (e) {
        return ctx.err('打印错误')
    }
}
const printTitle = ( invoice, tenantName,  print_at, ctx) => {
    let printNo = parseInt(invoice.printNo) + 1;
    let typename = "";
    switch (invoice.transType) {
        case 150501:
            typename = " 购货单";
            break;
        case 150502:
            typename = " 采购退货单";
            break;
        case 150603:
            typename = " 换货单";
            break;
        case 150601:
            typename = " 销售单";
            break;
        case 150602:
            typename = " 销售退货单";
            break;
        case 153001:
            typename = " 收款单";
            break;
        case 153101:
            typename = " 付款单";
            break;
        case 153401:
            typename = " 收入单";
            break;
        case 153402:
            typename = " 一般费用单";
            break;
        case 153403:
        case 153407:
            typename = " 预收款";
            break;
        case 160001:
            typename = " 转账单";
            break;
        case 153406:
            typename = " 预付款";
            break;
        case 153404:
            typename = " 应付单";
            break;
        case 153405:
            typename = " 应收单";
            break;
        case 150706:
            typename = " 其它入库";
            break;
        case 150806:
            typename = " 其它出库";
            break;
        default:
            return ctx.err("暂未更新该类票据打印");
    }
    if (invoice.billState === 'wasted') typename = typename + " - 退审票";
    if (invoice.billState === 'del') typename = typename + " - 已删票";
    let st = `<table cellpadding='0' cellspacing='0' style='border-collapse: collapse;width: 100%;' >
<thead> 
<tr>
    <td style='text-align: center;height: 40px'; colspan='8'>
        <div >
            <div style='font-size: 22px'>${tenantName}</div>
            <div style='font-size: 18px'>（${typename}）</div>
        </div>
        <div style='position: absolute;left: 2px;top:10px;font-size: 13px;font-weight: normal'>
            <div style='text-align:left'>日期：${invoice.billDate}</div>
            <div style='text-align:left'>票号：${invoice.billNo}</div>
        </div>
        <div style='position: absolute;right: 2px;top:5px;font-size: 12px;font-weight: normal'>
            <span tdata='PageNO'>##</span><span>/</span><span tdata='PageCount'>##</span>页 <span></span> ${print_at}-<span>${printNo}</span>
        </div>
    </td>
</tr>
`
    return  ctx.suc('', st)
}
const printHeadInfo = ( invoice,  vInvoice, ctx) => {
    let customerName = vInvoice.buName
    let customerPhone = vInvoice.linkMobile
    let customerAddress = vInvoice.address
    let transType = invoice.transType
    let info = []
    switch (transType) {
        case 150501:
        case 150706:
        case 150502: info.push(`<tr><td colspan='7' style='font-size: 14px'><div >客户：${customerName}</div></td></tr>`)
            break;
        case 150601:
        case 150602:
        case 150603:
        case 150806: {
            info.push("<tr><td colspan='8' style='font-size: 14px'>");
            info.push(`<div ><span>客户：${customerName}</span></div>`);
            info.push(`<div ><span >电话：${customerPhone}</span><span style='margin-left: 10px;'>地址：${customerAddress}</span></div>`);
            info.push("</td></tr>");
        }
            break;
        case 153001:
        case 153101:
        case 153401:
        case 153402:
        case 153403:
        case 153404:
        case 153405:
        case 153406:
        case 153407: info.push(`<tr><td colspan='7' style='font-size: 14px'><div >单位：${customerName}</div></td></tr>`);
            break;
        case 160001:
            info.push("<tr><td colspan='7' style='font-size: 14px;height: 30px;'><div ></div></td></tr>");
            break;
        default:
            return ctx.err("暂未更新该类票据打印");
    }
    return ctx.suc('', info.join(''))
}
const printTableHead = ( invoice, ctx) => {
    let transType = parseInt(invoice.transType)
    let info = []
    switch (transType) {
        case 150501:
        case 150706:
        case 150502: {
            info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>商品名称</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 75px;text-align: center;padding: 2px;'>辅助</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 40px;text-align: center;padding: 2px;'>单位</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 40px;text-align: center;padding: 2px;'>数量</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;text-align: center;padding: 2px;'>单价</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 70px;text-align: center;padding: 2px;'>金额</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody >");
        }
            break;
        case 150603: {
            info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>商品名称</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 75px;text-align: center;padding: 2px;'>辅助</td>");
            info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 40px;text-align: center;padding: 2px;'>单位</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;;text-align: center;padding: 2px;'>数量</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 65px;text-align: center;padding: 2px;'>单价</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 70px;text-align: center;padding: 2px;'>金额</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody >");
        }
            break;
        case 150601: {
            info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;word-break:break-all;text-align: center;padding: 2px;'>商品名称</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 75px;text-align: center;padding: 2px;'>辅助</td>");
            info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 40px;text-align: center;padding: 2px;'>单位</td>");
            info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;text-align: center;padding: 2px;'>数量</td>");
            info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;text-align: center;padding: 2px;'>单价</td>");
            info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;text-align: center;padding: 2px;'>返利</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 70px;text-align: center;padding: 2px;'>金额</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 70px;word-break:break-all;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody>");
        }
            break;
        case 150806:
        case 150602: {
            info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>商品名称</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 75px;text-align: center;padding: 2px;'>辅助</td>");
            info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 40px;text-align: center;padding: 2px;'>单位</td>");
            info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;text-align: center;padding: 2px;'>数量</td>");
            info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;text-align: center;padding: 2px;'>单价</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 70px;text-align: center;padding: 2px;'>金额</td>");
            info.push(" <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody>");
        }
            break;
        case 153001: {
            info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 160px;text-align: center;padding: 2px;'>收款账户</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 120px;text-align: center;padding: 2px;'>收款金额</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 120px;text-align: center;padding: 2px;'>收款优惠</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody>");
        } break;
        case 153101: {
            info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 160px;text-align: center;padding: 2px;'>付款账户</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 120px;text-align: center;padding: 2px;'>付款金额</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 120px;text-align: center;padding: 2px;'>付款优惠</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody>");
        } break;
        case 153401:
        case 153402:
        case 153403:
        case 153404:
        case 153405:
        case 153406:
        case 153407:
            if (transType == 153403) {
                info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: center;padding: 2px;'>商品名称</td>");
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: center;padding: 2px;'>单位</td>");
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: center;padding: 2px;'>数量</td>");
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: center;padding: 2px;'>单价</td>");
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: center;padding: 2px;'>金额</td>");
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody>");
            } else {
                info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 160px;text-align: center;padding: 2px;'>账户</td>");
                info.push("<td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 180px;text-align: center;padding: 2px;'>科目</td>");
                info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 120px;text-align: center;padding: 2px;'>金额</td>");
                info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody>");
            }
            break;
        case 160001: {
            info.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 160px;text-align: center;padding: 2px;'>转出账户</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 160px;text-align: center;padding: 2px;'>转入账户</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 120px;text-align: center;padding: 2px;'>转账金额</td>");
            info.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;'>备注</td></tr></thead><tbody>");
        }
            break;
    }
    return ctx.suc('', info.join(''))
}
const printTable = async ( invoice,vInvoice, ctx) => {
    let transType = parseInt(invoice.transType);
    let info = []
    let amount = 0
    let disAmount = tool.xe.toNumber(invoice.disAmount)
    let ysAmount = tool.xe.toNumber(invoice.ysAmount)
    let rpAmount = tool.xe.toNumber(invoice.rpAmount)
    let arrears = tool.xe.toNumber(invoice.arrears)
    switch (transType) {
        case 150501:
        case 150502:
        case 150706: {
            let list = await db.models['invoiceInfo'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            for (let i = 0; i < list.length; i++) {
                let it = list[i]
                if (!it.invId) continue
                info.push(`<tr><td style='border: 1px solid black;padding: 2px;text-align: left;'>${it.invName}</td>`);
                info.push(`  <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.assQty}</td>`);
                info.push(`  <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.unit}</td>`);
                info.push(`  <td style='border: 1px solid black;text-align: right;padding: 2px'>${it.qty ? it.qty : ''}</td>`);
                info.push(`  <td style='border: 1px solid black;text-align: right;padding: 2px'>${it.price}</td>`);
                info.push(` <td style='border: 1px solid black;text-align: right;padding: 2px'>${it.amount ? it.amount : ''}</td>`);
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.remark ? it.remark : ''}</td></tr>`);
            }
            // 如有收付款 再加一行
            if (rpAmount != 0) {
                let s = transType == 150502 ? "已收：" : "已付：";
                info.push(`<tr><td colspan='5' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>${s}</td>`);

                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${-rpAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 如有预收金额 再加一行
            if (ysAmount != 0) {
                info.push("<tr><td colspan='5' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>预付：</td>");
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${-ysAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 应收 应付
            if (arrears != 0) {
                let s = transType == 150502 ? "应收：" : "应付：";
                info.push(`<tr><td colspan='5' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>${s}</td>`);
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${arrears}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
        }
            break;
        case 150601: {
            let list = await db.models['invoiceInfo'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            let fl = 0
            for (let i = 0; i < list.length; i++) {
                let it = list[i]
                if (!it.invId) continue;
                let dedu = tool.xe.toNumber(it.deduction)
                fl = tool.xe.add(fl, tool.xe.multiply(it.qty, dedu))
                amount = tool.xe.add(amount, it.amount)
                let send = it.send
                let remark = it.remark
                let mark = send + remark
                info.push(` <tr><td style='border: 1px solid black;padding: 2px; text-align: left;'>${it.invName}</td>`)
                info.push(`   <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.assQty}</td>`)
                info.push(`    <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.unit}</td>`)
                info.push(`    <td style='border: 1px solid black;text-align: right;padding: 2px'>${it.qty}</td>`)
                info.push(`    <td style='border: 1px solid black;text-align: right;padding: 2px'>${tool.xe.toNumber(it.price)?it.price: ''}</td>`)
                info.push(`   <td style='border: 1px solid black;text-align: right;padding: 2px'>${tool.xe.toNumber(it.deduction)?it.deduction:''}</td>`)
                info.push(` <td style='border: 1px solid black;text-align: right;padding: 2px'>${tool.xe.toNumber(it.amount)?it.amount:''}</td>`)
                info.push(`  <td style='border: 1px solid black;padding: 2px;text-align: center;font-size: 12px;text-align:left;'>${mark}</td></tr>`);
            }
            // 如有优惠金额 再加一行
            if (disAmount != 0) {
                info.push("<tr><td colspan='3' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td  style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td colspan='2' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>优惠金额：</td>");
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: right;'>${-disAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 如有预收金额 再加一行
            if (ysAmount != 0) {
                info.push("<tr><td colspan='3' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td  style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td colspan='2' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>预收：</td>");
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${-ysAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 如有收款金额 再加一行
            if (rpAmount != 0) {
                info.push("<tr><td colspan='3' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td  style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td colspan='2' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>已收：</td>");
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${-rpAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 最后合计应收
            if (arrears != 0) {
                info.push("<tr><td colspan='3' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td>" + "<td  style='border: 1px solid black;padding: 2px;text-align: right;'>")
                info.push(`${invoice.qty}</td><td colspan='2' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>应收合计：</td>`)
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${invoice.arrears}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
        }
            break;
        case 150602: {
            let list = await db.models['invoiceInfo'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            let fl = 0
            for (let i = 0; i < list.length; i++) {
                let it = list[i]
                if (!it.invId) continue;
                let dedu = tool.xe.toNumber(it.deduction)
                fl = tool.xe.add(fl, tool.xe.multiply(it.qty, dedu))
                amount = tool.xe.add(amount, it.amount)
                info.push(` <tr><td style='border: 1px solid black;padding: 2px;text-align: left;'>${it.invName}</td>`)
                info.push(`   <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.assQty}</td>`)
                info.push(`    <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.unit}</td>`)
                info.push(`    <td style='border: 1px solid black;text-align: right;padding: 2px'>${it.qty}</td>`)
                info.push(`    <td style='border: 1px solid black;text-align: right;padding: 2px'>${it.price}</td>`)
                info.push(` <td style='border: 1px solid black;text-align: right;padding: 2px'>${it.amount}</td>`)
                info.push(`  <td style='border: 1px solid black;padding: 2px;text-align: center;'>${it.remark}</td></tr>`);
            }
            // 如有优惠金额 再加一行
            if (disAmount != 0) {
                info.push("<tr><td colspan='3' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td> <td   style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'> </td>" +
                    "<td style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>减扣：</td>");
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${-disAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 如有收款金额 再加一行
            if (rpAmount != 0) {
                info.push("<tr><td colspan='3' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td   style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'> </td>" +
                    "<td  style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>已付：</td>");
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${-rpAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 最后合计应收
            if (arrears != 0) {
                info.push("<tr><td colspan='3' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'></td><td   style='border: 1px solid black;padding: 2px;text-align: right; '>")
                info.push(`${invoice.qty}</td><td  style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>应付：</td>`)
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${invoice.arrears}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
        }
            break;
        case 150603: {
            let list = await db.models['invoiceInfo'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            let  tin = []
            let tout = []
            for (let i = 0; i < list.length; i++) {
                let it = list[i]
                if(it.trans == '换入') {
                    tin.push(it);
                }
                if(it.trans == '换出') {
                    tout.push(it);
                }
            }
            for (let i = 0; i < tin.length; i++) {
                let it = tin[i]
                if (!it.invId) continue;
                let invName = it.invName;
                let unit = it.unit;
                let quantity = -tool.xe.toNumber(it.qty)
                let assisQty = it.assQty;
                let deduction = it.deduction
                let prices = it.price
                let price = tool.Np.minus(prices, deduction)
                let sub = -tool.xe.toNumber(it.amount)
                let beizhu = it.send + it.remark
                info.push("<tr ><td style='border: 1px solid black;padding: 2px;text-align: left;'>")
                info.push(`<span  style='border-right: 1px solid grey;padding-right:5px;font-weight:800;'>换入</span><span>${invName}</span></td>`)
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: center;'>${assisQty}</td>`)
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: center;'>${unit}</td>`)
                info.push(`<td style='border: 1px solid black;text-align: center;padding: 2px'>${quantity}</td>`)
                info.push(`<td style='border: 1px solid black;text-align: right;padding: 2px'>${price}</td>`)
                info.push(`<td style='border: 1px solid black;text-align: right;padding: 2px'>${sub}</td>`)
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: center;'>${beizhu}</td></tr>`);
            }
            for (let i = 0; i < tout.length; i++) {
                let it = tin[i]
                if (!it.invId) continue;
                let invName = it.invName;
                let unit = it.unit;
                let quantity = tool.xe.toNumber(it.qty)
                let assisQty = it.assQty;
                let deduction = it.deduction
                let prices = it.price
                let price = tool.Np.minus(prices, deduction)
                let sub = it.amount
                let beizhu = it.send + it.remark
                info.push("<tr><td style='border: 1px solid black;padding: 2px;text-align: left;'>")
                info.push(`     <span style='border-right: 1px solid grey;padding-right:5px;font-weight:800;'>换出</span><span>${invName}</span></td>`)
                info.push(`  <td style='border: 1px solid black;padding: 2px;text-align: center;'>${assisQty}</td>`)
                info.push(`   <td style='border: 1px solid black;padding: 2px;text-align: center;'>${unit}</td>`)
                info.push(`   <td style='border: 1px solid black;text-align: center;padding: 2px'>${quantity}</td>`)
                info.push(`   <td style='border: 1px solid black;text-align: right;padding: 2px'>${price}</td>`)
                info.push(`   <td style='border: 1px solid black;text-align: right;padding: 2px'>${sub}</td>`)
                info.push(`   <td style='border: 1px solid black;padding: 2px;text-align: center;'>${beizhu}</td></tr>`);
            }
            // 如有优惠金额 再加一行
            if (disAmount != 0) {
                info.push("<tr><td colspan='5' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>优惠金额：</td>")
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: right;'>${-disAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 如有预收金额 再加一行
            if (ysAmount != 0) {
                info.push("<tr><td colspan='5' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>预收抵扣：</td>")
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: right;'>${-ysAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 如有收款金额 再加一行
            if (rpAmount != 0) {
                info.push("<tr><td colspan='5' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>已收：</td>")
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: right;'>${-rpAmount}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
            // 最后合计应收
            if (arrears != 0) {
                info.push("<tr><td colspan='5' style='border: 1px solid black;padding: 2px;text-align: right;font-size: 12px;'>应收：</td>")
                info.push(` <td style='border: 1px solid black;padding: 2px;text-align: right;'>${invoice.arrears}</td><td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>`);
            }
        }
            break;
        // 收款单
        case 153001:
        // 付款单
        case 153101: {
            let beizhu =  invoice.remark;
            if (invoice.accId) {
                info.push(`<tr><td style='border: 1px solid black;padding: 2px;text-align: left;'>${vInvoice.accName}</td>`)
                info.push(`<td style='border: 1px solid black;text-align: right;padding: 2px'>${vInvoice.accAmount}</td>`)
                info.push(`<td style='border: 1px solid black;text-align: right;padding: 2px'>${vInvoice.disAmount}</td>`)
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: center;'>${beizhu}</td></tr>`);
            }
            if (invoice.accId1) {
                info.push(`<tr><td style='border: 1px solid black;padding: 2px;text-align: left;'>${vInvoice.accName1}</td>`)
                info.push(`<td style='border: 1px solid black;text-align: right;padding: 2px'>${vInvoice.accAmount1}</td>`)
                info.push(" <td style='border: 1px solid black;text-align: right;padding: 2px'></td>")
                info.push(" <td style='border: 1px solid black;padding: 2px;text-align: center;'></td></tr>");
            }

        } break;
        // 预付
        case 153401: // 通用收入
        case 153402: // 通用支出
        case 153406:
        // 预收
        case 153407: {
            let list1 = await db.query(`select * from invoice_other where iid=${invoice.id}`)
            for (let i = 0; i < list1.length; i++) {
                let it = list1[i]
                let payment = tool.xe.toNumber(it.amount)
                if(payment != 0) {
                    let beizhu =  it.remark
                    info.push(`<tr><td style='border: 1px solid black;padding: 2px;text-align: left;'>${it.accName}</td>`);
                    info.push(`<td style='border: 1px solid black;padding: 2px;text-align: left;'>${it.subjectName}</td>`);
                    info.push(`<td style='border: 1px solid black;text-align: right;padding: 2px'>${payment}</td>`);
                    info.push(`<td style='border: 1px solid black;padding: 2px;text-align: center;'>${beizhu}</td></tr>`);
                }
            }
        }
            break;
        case 153403: {
            let list1 = await db.query(`select * from invoice_info_ys where iid=${invoice.id}`)
            for (let i = 0; i < list1.length; i++) {
                let invoiceInfoYs = list1[i]
                let price = invoiceInfoYs.price
                let amounts = invoiceInfoYs.amount
                let beizhu =  invoiceInfoYs.remark
                let bd = i==list1.length-1 ? "border-bottom: 1px solid black;" : "";
                info.push(`<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 260px;text-align: left;padding: 2px;${bd}'>${invoiceInfoYs.invName}</td>`)
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 40px;text-align: center;padding: 2px;")
                info.push(`${bd}'>${invoiceInfoYs.unit}</td>`)
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 40px;text-align: right;padding: 2px;")
                info.push(`${bd}'>${invoiceInfoYs.qty}</td>`)
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 50px;text-align: right;padding: 2px;")
                info.push(`${bd}'>${price}</td>`)
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 70;text-align: right;padding: 2px;")
                info.push(`${bd}'>${amounts}</td>`)
                info.push("  <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: center;padding: 2px;")
                info.push(`${bd}'>${beizhu}</td></tr></thead><tbody>`);
            }
        } break;
        case 160001: {
            let listTrans = await db.query(`select * from invoice_trans where iid=${invoice.id}`)
            for (let i = 0; i < listTrans.length; i++) {
                let it = listTrans[i]
                let remark = it.remark
                info.push(`<tr><td style='border: 1px solid black;padding: 2px; text-align: left;'>${it.accName}</td>`)
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: left;'>${it.accName1}</td>`)
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: right;'>${it.amount}</td>`)
                info.push(`<td style='border: 1px solid black;padding: 2px;text-align: left;font-size: 12px;'>${remark}</td></tr>`)
            }
        }
    }

    return ctx.suc('', info.join(''))
}
const printTfoot = ( invoice,  vInvoice,  descript, ctx) =>  {
    let transType = parseInt(invoice.transType)
    let info = []
    let totalAmount = tool.xe.toNumber(invoice.totalAmount)
    let rpAmount = tool.xe.toNumber(invoice.rpAmount)
    let arrears = tool.xe.toNumber(invoice.arrears)
    let ysAmount = tool.xe.toNumber(invoice.ysAmount)
    let doName = vInvoice.doName
    let userName = vInvoice.cbyName
    let salesName = vInvoice.salesName
    let deliverNames = vInvoice.deliverNames
    switch (transType) {
        case 150501:
        case 150706:
        case 150502: {
            let c = tool.Np.minus(totalAmount, rpAmount, ysAmount)
            if (c != arrears) {
                return ctx.err("票据金额不等于应收/付金额");
            }
            info.push("</tbody><tfoot  >")
            info.push(`    <tr><td colspan='7' style='border: 1px solid black;font-size: 14px;padding: 5px 0'>`)
            info.push(`   <span>金额${arrears}</span>&nbsp;&nbsp;大写<span format='UpperMoney' tdata='${arrears}'>#</span></td></tr>`)
            info.push(`<tr><td colspan='7' style='font-size: 14px'> <span>制单人:${userName}</span><span style='margin-left: 50px'>收货人:${deliverNames}</span></td></tr></tfoot>`)
        }
            break;
        case 150603:{
            let str = `</tbody><tfoot ><tr><td colspan='7' style='border: 1px solid black;padding: 5px 0'>金额：${arrears} 
大写：<span format='UpperMoney' tdata='${arrears}'>#</span></td></tr>
`
            info.push(str)
            if(descript) {
                info.push(`<tr><td colspan='7' style='padding-top: 2px;'>${descript}</td></tr>`);
            }
            info.push(`<tr> <td colspan='7'><table style='width: 100%'><tbody><tr>`)
            info.push(`              <td style='width: 100px;'>送货员:</td><td >制单人:${userName}</td> <td >业务员:${salesName}</td>`)
            info.push(`              <td  style='width: 150px;'>未付款签字：</td>`)
            info.push(`        </tr></tbody></table></td></tr></tfoot>`)
        }
            break;
        case 150806:
        case 150601:{
            info.push(" </tbody><tfoot ><tr>");
            info.push(`      <td colspan='8' style='border: 1px solid black;padding: 5px 0;font-size: 13px'><span>金额：${arrears} </span>`);
            info.push(`大写：<span format='UpperMoney' tdata='${arrears}'>#</span></td> </tr>`);
            if(descript) {
                info.push(` <tr><td colspan='8' style=' padding-top: 2px;font-size: 12px;'>${descript}</td></tr>`);
            }
            info.push(`<tr><td colspan='8' style='font-size: 14px'><table style='width: 100%'><tbody><tr><td style='width: 100px;'>送货员:</td><td >制单人:${userName}</td>`)
            info.push(`        <td >业务员:${salesName}</td><td  style='width: 150px;'>未付款签字：</td></tr></tbody></table></td></tr></tfoot>`);
        }
            break;
        case 150602: {
            info.push(" </tbody> <tfoot ><tr>");
            info.push(`       <td colspan='7' style='border: 1px solid black;padding: 5px 0'>金额：${arrears}`);
            info.push(` 大写：<span format='UpperMoney' tdata='${arrears}'>#</span></td> </tr>`);
            if(descript) {
                info.push(`<tr><td colspan='7' style=' padding-top: 2px;font-size: 12px;'>${descript}</td></tr>`);
            }
            info.push("<tr><td colspan='7' style='font-size: 14px'><table style='width: 100%'>")
            info.push(` <tbody> <tr><td style='width: 100px;'>送货员:</td><td >制单人:${userName}`)
            info.push(`</td> <td >业务员:${salesName}`)
            info.push("</td><td  style='width: 150px;'>未付款签字：</td></tr></tbody></table></td></tr></tfoot>");
        }
            break;
        case 153001:
        case 153101:
        case 153401:
        case 153402:
        case 153403:
        case 153404:
        case 153405:
        case 153406:
        case 153407: {
            if (transType == 153403) {
                info.push( " </tbody>" +
                    "<tfoot > <tr><td colspan='2' style='border: 1px solid black;text-align: left;padding:2px 2px 2px 0; ' > 总计： </td>");
                info.push( "    <td style='border: 1px solid black;text-align: right;padding-right: 2px' tdata='SubSum' format='0'>###</td> " +
                    "<td style='border: 1px solid black;text-align: right;padding-right: 2px'   ></td>");
                info.push( "    <td style='border: 1px solid black;text-align: right;padding-right: 2px' tdata='SubSum' format='0.00'>########</td>");
                info.push( "    <td style='border: 1px solid black'></td></tr>");
                info.push(`<tr><td > 制单人:${userName} </td> <td colspan='2' >经办人：${doName} </td><td > </td> </tr></tfoot>`);
            } else {
                info.push( " </tbody><tfoot > <tr><td  style='border: 1px solid black;text-align: left;padding:2px 2px 2px 0;width:200px' >")
                info.push( "  合计：")
                info.push( "     </td> <td tindex='2' tdata='AllSum' format='0.00' style='border: 1px solid black;text-align: right;padding-right: 2px'  >########</td>")
                info.push( "    <td tindex='3' tdata='AllSum' format='0.00' style='border: 1px solid black;text-align: right;padding-right: 2px'  >########</td><td style='border: 1px solid black'></td></tr>")
                info.push(`<tr><td > 制单人:${userName} </td> <td >经办人：${doName}  </td><td > </td></tr></tfoot>`);
            }
        }
            break;
        case 160001: {
            info.push(" </tbody><tfoot ><tr>");
            info.push(`      <td colspan='2' style='border: 1px solid black;padding: 5px 0;font-size: 13px'></td> 
                <td style='border: 1px solid black;text-align: right;'>${invoice.amount}</td> 
                <td style='border: 1px solid black;padding: 5px 0;font-size: 13px;text-align: left;'></td></tr>`);
            info.push(`<tr><td colspan='8' style='font-size: 14px'><table style='width: 100%'><tbody><tr><td >制单人:${userName}</td>`)
            info.push("</tr></tbody></table></td></tr></tfoot>");
        }
            break;
    }
    return ctx.suc('', info.join(''))
}

const getOptionsByName = async (tenantId, name) => {
    let ret = await db.models['options'].findOne({
        where: {
            tenantId,
            name
        }
    })
    return ret
}
// 更新辅助数量
const updateAssisQty = async ( ctx) => {
    let body = ctx.request.body
    let tid = ctx.user.tenantId
    let transType = ctx.request.body.transType
    if ([150601,150602,150603,150501,150502,150706,150806,153403].indexOf(transType) !== -1 ) {
        let arr = []
        let infos = body.invoiceInfos
        if(transType === 153403) {
            infos = body.invoiceInfoYs
        }
        for (let i = 0; i < infos.length; i++) {
            let row = infos[i]
            if(row.invId) {
                arr.push(`select ${row.invId} invId,${row.calNum} calNum,${row.spec} spec, '${row.unit}' unit ,${tool.Np.times(row.qty,row.calNum)} qty`)
            }
        }
        if(arr.length > 0) {
            let sql = ` select a.*,b.spec oldSpec,b.unit1,b.unit2,b.name invName from (${arr.join(' union all ')}) a inner join goods b on a.invId=b.id and b.tenantId=${tid}`
            let list = await db.query(sql, {type: QueryTypes.SELECT})
            if(list.length !== arr.length) throw Error('商品档案错误')
            for (let i = 0; i < list.length; i++) {
                let row = list[i]
                if(row.spec != row.oldSpec) throw Error(`商品规格设置错误，规格${row.spec} 不等于 ${row.oldSpec}`)
                if(tool.xe.toNumber(row.qty) <= 0) throw Error(infos[i].invName + '商品数量不能小于0')
                if(row.qty.toString().split('.').length > 1) throw Error(row.invName + '最小单位数量不能是小数')
                if(transType === 153403) {
                    ctx.request.body.invoiceInfoYs[i].assQty = calAssQty(row.qty,row.spec,row.unit1, row.unit2)
                }
                else {
                    ctx.request.body.invoiceInfos[i].assQty = calAssQty(row.qty,row.spec,row.unit1, row.unit2)
                }
            }
        }
        else {
            throw Error('没有明细数据')
        }
    }
}
const calAssQty = (qty,spec,unit1,unit2) => {
    if(!spec) throw Error('规格不能为 0 ')
    let mai = Math.floor(qty/spec) > 0 ? `${Math.floor(qty/spec)}${unit1}`:''
    let sub = qty%spec > 0 ? `${qty%spec}${unit2}` : ''
    return mai+sub
}
// 当前账期
const currentZq = async (tenantId) => {
    let zq = await db.models['zq'].findOne({
        where: {
            tenantId,
            isCurrent: 1
        }
    })
    if (!zq) throw Error('请先启用账套')
    return zq;
}
//
const saveLogInvoice = async ( tenantId,  uid,  id,  op,  data, t) =>{
    let log = db.models['invoiceLog'].build()
    log.tenantId = tenantId
    log.op = op
    log.iid = id
    log.uid = uid
    log.data = JSON.stringify(data)
    if(typeof t !== 'undefined') {
        await log.save({transaction: t})
    }
    else {
        await log.save()
    }
}
// 是否可以记账
const billCanEdit = async (ym,tenantId) => {
    let zq = await currentZq(tenantId);
    let zqYm = ym.substring(0,4) + ym.substring(5, 7);
    let  currentYm = zq.ym.substring(0, 4) + zq.ym.substring(5, 7);
    if (parseInt(zqYm) < parseInt(currentYm)) throw Error(`【${ym}】已结账。`)
}
// 记账
const toAccounted = async (ctx) => {
    let body = ctx.request.body
    let ter = body.ter
    let tenantId = ctx.user.tenantId
    let uid = ctx.user.id
    let isScan = body.byScan ? 1: 0
    let menuId = body.menuId
    let ids = body.ids
    let byCell = ter === 'app' ? 1 : 0;
    // 查看id中的数据合法性
    let list = await db.models['invoice'].findAll({
        where: {
            tenantId,
            billState: 'draft',
            id: {
                [Op.in]: ids,
            }
        }
    })
    if (list.length !== ids.length) throw Error("要记账的草稿条数不等于记账条数");
    let billType = "";
    let transType;
    for (let i = 0; i < list.length; i++) {
        let invoice = list[i]
        transType = invoice.transType
        // 是否能操作
        await billCanEdit(invoice.billDate, tenantId)
        switch (transType) {
            case 153001: // 收/付款
            case 153101: {
                // 检测是否多收付款了。
                // detectHxAmount(tenantId, ids);
            }
                break;
            // 预收商品
            case 153403: {

            } break;
            case 153406: // 预付/收款
            case 153407: {
            }
                break;
        }
    }
    await db.transaction(async t => {
        for (let i = 0; i < list.length; i++) {
            let invoice = list[i]
            transType = invoice.transType
            let model = await db.models['invoice'].findOne({
                where: {
                    id: invoice.id
                }
            })
            model.accountedBy = uid;
            model.accountedAt = tool.getTime()
            model.billState = 'accounted';
            await model.save({transaction: t})
            // 更新库存
            if(['PUR','SALE','OO','OI'].indexOf(invoice.billType) !== -1) {
                await db.models['invoiceInfo'].update({
                    billState: 'accounted'
                }, {
                    where: {
                        iid: invoice.id
                    }
                }, {transaction: t})
                await db.models['inventoryDetail'].update({
                    isCal: 1
                }, {
                    where: {
                        iid: invoice.id
                    }
                }, {transaction: t})
               await updateInventoryByBill(ctx, invoice.id, t)
            }
            // 生成记账日志
            await saveLogInvoice(tenantId, uid, invoice.id, "记账", invoice, t);
            billType = invoice.billType
        }
    })
}
// 检测是否有收款单据
const detectHasReceipt = async (tenantId, id) => {
    let c = `select count(0) num from invoice a inner join invoice_receipt as b on a.id=b.iid and a.tenantId=${tenantId} and b.billId=${id} `
    let has = await db.query(c, {type:QueryTypes.SELECT, plain: true})
    if(has.num)
        throw Error('已有收/付款记录')
}
// 检测预收商品
const detectYsGoods = async ( invoiceInfo) => {
    let ysId = invoiceInfo.ysId;
    let price = invoiceInfo.price?tool.xe.toNumber(invoiceInfo.price):0
    let unit = invoiceInfo.unit
    let invoiceInfoYs = await db.models['invoiceInfoYs'].findOne({
        where: {
            id: ysId
        }
    })
    if (!invoiceInfoYs) throw Error('未找到相应预收商品项目')
    let price1 = invoiceInfoYs.price?tool.xe.toNumber(invoiceInfoYs.price):0
    let unit1 = invoiceInfoYs.unit
    if (price1 !== price)  throw Error("不允许更改预收商品价格");
    if (unit1 !== unit) throw Error("不允许更改预收商品单位");
}
// 保存业务票据
const saveInvoiceData = async (ctx) => {
    await detectStock(ctx)
    await updateAssisQty(ctx)
    let body = ctx.request.body
    let user = ctx.user
    let uid = ctx.user.id
    let tenantId = user.tenantId
    let transType = body.transType
    let billType = body.billType
    let transTypeName = body.transTypeName
    if (!body.billDate) return ctx.err('请选择开票日期');
    if (!transType || !billType || !transTypeName) return ctx.err('未知票据类型');
    let isAdd = true
    // 新增
    if (!body.id) {
        body.billNo = await setBillNo(ctx)
    }
    // 修改
    else {
        // 票据是否属于当前用户
        let invo = await db.models['invoice'].findOne({
            where: {
                tenantId,
                id: body.id
            }
        })
        if (!invo) return ctx.err('未找到票据或者已被删除');
        isAdd = false
    }
    let op = isAdd ? "新增" : "修改";
    let byCell = body.ter === 'cell' ? 1 : 0
    let billDate = body.billDate
    let bm = tool.dayjs(billDate).month()
    let cm = tool.dayjs(tool.getDay()).month()
    if(Math.abs(bm-cm) > 1) {
        return ctx.err('禁止跨多月录入数据')
    }
    try {
        let invoice = ctx.request.body
        let invoiceInfos = []
        tool.setDefault(invoice, 'invoice')
        invoice.postData = JSON.stringify(invoice)
        switch (billType) {
            case "OI":
            case "OO":
            case "PUR":
            case "SALE": {
                invoiceInfos = ctx.request.body.invoiceInfos
            }
                break;
            case "RECEIPT":
            case "PAYMENT": {
                invoiceInfos = ctx.request.body.invoiceReceipts
            }
                break;
            case "YSK":
            case "YFK":
            case "SR":
            case "ZC": {
                invoiceInfos = ctx.request.body.invoiceOthers
            }
                break;
            case "ZZ": {
                invoiceInfos = ctx.request.body.invoiceTrans
            }
                break;
        }
        if(invoiceInfos.length === 0)  return ctx.err("没有明细数据");
        // 票据是否能编辑
//         billCanEdit(invoice.getBillDate(), tenantId);
        invoice.billState = 'draft'
        invoice.tenantId = tenantId
        let billAt = invoice.billDate
        invoice.updatedAt = tool.getTime()
        let deliverIds = invoice.deliverIds ? (invoice.deliverIds == '[]' ? "" : invoice.deliverIds) : ""
        let deliverNames = invoice.deliverNames
        if (!deliverIds) {
            if (deliverIds == '0') deliverIds = "";
            if (deliverIds.indexOf("0,") == 0) {
                deliverIds = deliverIds.substring(2);
            }
            if (deliverIds.indexOf("NaN,") == 0) {
                deliverIds = deliverIds.substring(4);
            }
        }
        let salesId = invoice.salesId?invoice.salesId:null
        let salesName = invoice.salesName?invoice.salesName:null
        if (isAdd) {
            invoice.byCell = byCell;
            // 检查权限
            invoice.createdAt = tool.getTime()
            invoice.cby = uid
        }
        else {
            // 检查权限
            let invoice1 = await db.models['invoice'].findOne({
                where: {id: invoice.id}
            })
            let isInit = invoice1.isInit
            if (isInit) {
                return ctx.err("不能退审期初数据");
            }
            if (invoice1.billState === 'del') return ctx.err("不能修改已删除数据");
            if (invoice1.billState === 'accounted') return ctx.err("不能修改已记账数据");
        }
        if (!salesName) if (salesId) return ctx.err("请选择销售员");
        if (salesId) if (!salesName) return ctx.err("请选择销售员");
        if (!invoice.billNo) return ctx.err("没有票据号");
        let accId = invoice.accId
        let accId1 = invoice.accId1
        let buId = invoice.buId
        let doBy = invoice.doId
        let yhAmount = 0; // 收付款优惠总金额
        let calAmount = 0;
        let qtys = 0;
        let totalDiscount = 0;

        let totalAmount = invoice.totalAmount ? invoice.totalAmount : 0 // 总金额
        let ysAmount = invoice.ysAmount ? invoice.ysAmount : 0 // 预收/预付
        let disAmount = invoice.disAmount ? tool.xe.toNumber(invoice.disAmount) : 0 // 票据优惠
        let rpAmount = invoice.rpAmount ? tool.xe.toNumber(invoice.rpAmount) : 0 // 收/付款金额
        let arrears = 0; // 本次欠款
        let accAmount = invoice.accAmount ? invoice.accAmount : 0 // 账户1金额
        let accAmount1 = invoice.accAmount1 ? invoice.accAmount1 : 0 // 账户2金额
        invoice.batchReceiptId = 0
        invoice.accId = accId
        invoice.accId1 = accId1
        invoice.accAmount = accAmount;
        invoice.accAmount1 = accAmount1;
        invoice.ysAmount = ysAmount;
        invoice.billYear = billAt.substring(0, 4)
        invoice.billMonth = billAt.substring(5, 7);
        invoice.buId = buId;
        invoice.doId = doBy;
        invoice.deliverIds = deliverIds;
        invoice.deliverNames = deliverNames;
        invoice.salesId = salesId;
        switch (transType) {
            case 150501:
            case 150502:
            case 150601:
            case 150602:
            case 150706:
            case 150806:
            case 150603: {
                let goods = ''
                if(invoice.accId) {
                    let s = "请输入账户金额";
                    if (transType == 150602 || transType == 150501) s = "请输入付款金额";
                    if (!rpAmount) return ctx.err(s);
                }
                if (rpAmount) {
                    if (!accId) return ctx.err("请选择账户");
                    if (rpAmount) {
                        let s = "本次收款大于待付金额";
                        if (transType == 150602 || transType == 150501) s = "本次付款大于待付金额";
                        if (totalAmount > 0) if (rpAmount > tool.Np.minus(totalAmount, disAmount)) {
                            return ctx.err(s);
                        }
                    }
                }
                for (let i = 0; i < invoiceInfos.length; i++) {
                    let invoiceInfo = invoiceInfos[i]
                    tool.setDefault(invoiceInfo, 'invoiceInfo')
                    if (!invoiceInfo.invId) continue;
                    invoiceInfo.tenantId = tenantId;
                    let subAmount = tool.xe.toNumber(invoiceInfo.amount)
                    let price = tool.xe.toNumber(invoiceInfo.price)
                    let qty = tool.xe.toNumber(invoiceInfo.qty)
                    if (qty <= 0) return ctx.err("数量不能小于 0 ");
                    // 算单价
                    switch (invoice.billType) {
                        case "PUR":
                        case "OI":
                        case "OO":
                            let cp = tool.Np.round(tool.Np.times(qty, price), 2)
                            if (cp !== subAmount) {
                                return ctx.err(invoiceInfo.invName  + "  金额不等于 数量 * 单价");
                            }
                            break;
                        case "SALE":
                            let deduction = tool.xe.toNumber(invoiceInfo.deduction)
                            let cp1 = tool.Np.round(tool.Np.times(tool.Np.minus(price, deduction), qty), 2)
                            if (cp1 != subAmount) {
                                return ctx.err(invoiceInfo.invName + "  金额不等于 数量 * 单价");
                            }
                            totalDiscount = tool.Np.plus(tool.Np.times(qty, deduction))
                            break;
                    }
                    let calNum = tool.xe.toNumber(invoiceInfo.calNum)
                    let detail = tool.Np.times(invoiceInfo.qty, calNum)
                    // 最小单位不能有小数
                    if (tool.xe.isFloat(detail)) {
                        return ctx.err(invoiceInfo.invName + "  最小单位数量不能为小数");
                    }
                    let sub = tool.xe.toNumber(invoiceInfo.amount)
                    switch (transType) {
                        case 150706:
                        case 150501: {
                            invoiceInfo.qtyReal = invoiceInfo.qty
                            invoiceInfo.amountReal = invoiceInfo.amount
                            calAmount = tool.Np.plus(calAmount, sub)
                            qtys = tool.Np.plus(qtys,qty)
                        }
                            break;
                        case 150806:
                        case 150502: {
                            invoiceInfo.qtyReal = -tool.xe.toNumber(invoiceInfo.qty)
                            invoiceInfo.amountReal = -tool.xe.toNumber(invoiceInfo.amount)
                            calAmount = tool.Np.plus(calAmount, sub)
                            qtys = tool.Np.plus(qtys,qty)
                        }
                            break;
                        case 150601: {
                            invoiceInfo.qtyReal = -tool.xe.toNumber(invoiceInfo.qty)
                            invoiceInfo.amountReal = -tool.xe.toNumber(invoiceInfo.amount)
                            calAmount = tool.Np.plus(calAmount, sub)
                            qtys = tool.Np.plus(qtys,qty)
                            // 如果有预收商品，检测数量，价格是否合适
                            if (invoiceInfo.ysId) {
                                await detectYsGoods(invoiceInfo);
                            }
                        }
                            break;
                        case 150602: {
                            invoiceInfo.qtyReal = tool.xe.toNumber(invoiceInfo.qty)
                            invoiceInfo.amountReal =  -tool.xe.toNumber(invoiceInfo.amount)
                            calAmount = tool.Np.plus(calAmount, sub)
                            qtys = tool.Np.plus(qtys,qty)
                        }
                            break;
                        case 150603: {
                            if (invoiceInfo.trans ==  "换入") {
                                calAmount = tool.Np.plus(calAmount, -sub)
                                invoiceInfo.qtyReal = tool.xe.toNumber(invoiceInfo.qty)
                                invoiceInfo.amountReal =  -tool.xe.toNumber(invoiceInfo.amount)
                                qtys = tool.Np.minus(qtys, qty)
                            }
                            if (invoiceInfo.trans == '换出') {
                                calAmount = tool.Np.plus(calAmount,sub)
                                invoiceInfo.qtyReal = -tool.xe.toNumber(invoiceInfo.qty)
                                invoiceInfo.qmountReal = tool.xe.toNumber(invoiceInfo.amount)
                                qtys = tool.Np.plus(qtys, qty)
                            }
                            if (!invoiceInfo.trans) {
                                return ctx.err(invoiceInfo.invName + "  选择换入还是换出");
                            }
                        }
                            break;
                    }
                    invoiceInfo.buId = invoice.buId
                    invoiceInfo.transType = invoice.transType
                    invoiceInfo.transTypeName = invoice.transTypeName
                    invoiceInfo.billType = invoice.billType
                    goods += `${invoiceInfo.invName},`
                }
                invoice.goods = goods
                invoice.accAmount = rpAmount;
            }
                break;
            case 153001:
            case 153101: {
                for (let i = 0; i < invoiceInfos.length; i++) {
                    let invoiceInfo = invoiceInfos[i]
                    tool.setDefault(invoiceInfo, 'invoiceReceipt')
                }

            }
            break
        }
        if (totalAmount != calAmount) return ctx.err("合计金额不等于总金额");
        arrears = tool.Np.minus(calAmount, rpAmount,disAmount, ysAmount)
        //
        invoice.yhAmount = yhAmount;
        invoice.totalAmount = calAmount;
        invoice.disAmount = disAmount;
        invoice.rpAmount = rpAmount;
        invoice.arrears = arrears;
        invoice.amount = tool.Np.minus(calAmount,disAmount,ysAmount)
        invoice.qty = qtys
        invoice.totalDiscount = totalDiscount;
        // 保存主表
        await db.transaction(async t => {
            if(isAdd) {
                delete invoice.id
                let model = await db.models['invoice'].create(invoice, {transaction: t})
                invoice.id = model.id
            }
            else {
                let model =  await db.models['invoice'].findOne({
                    where: {
                        id: invoice.id,
                        tenantId
                    }
                })
                if(!model) throw Error('查询原数据失败')
                await db.models['invoice'].update(invoice, {
                    where: {
                        id: invoice.id,
                        tenantId
                    }
                },{transaction: t})
            }
            switch (transType) {
                case 150501:
                case 150502:
                case 150601:
                case 150602:
                case 150603:
                case 150706:
                case 150806: {
                    if(!isAdd) {
                        await db.models['invoiceInfo'].destroy({
                            where: {
                                iid: invoice.id,
                                tenantId
                            }
                        }, {transaction: t})
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = invoice.id
                        invoiceInfos[i].billNo = invoice.billNo
                        invoiceInfos[i].buId = invoice.buId
                        invoiceInfos[i].transTypeName = invoice.transTypeName
                        invoiceInfos[i].transType = invoice.transType
                        invoiceInfos[i].tenantId = tenantId
                        invoiceInfos[i].billState = invoice.billState
                    }
                    await db.models['invoiceInfo'].bulkCreate(invoiceInfos, {transaction: t})
                }
                    break;
                case 153001: // 收款
                case 153101: { // 付款
                    if(!isAdd) {
                        await db.models['invoiceReceipt'].destroy({
                            where: {
                                tenantId,
                                iid: invoice.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        delete invoiceInfos[i].id
                        invoiceInfos[i].iid = invoice.id
                        invoiceInfos[i].billNo = invoice.billNo
                        invoiceInfos[i].tenantId = invoice.tenantId
                        invoiceInfos[i].transType = invoice.transType
                        invoiceInfos[i].billType = invoice.billType
                        invoiceInfos[i].transTypeName = invoice.transTypeName
                    }
                    await db.models['invoiceReceipt'].bulkCreate(invoiceInfos, {transaction: t})
                } break
                case 153403: {
                    if(!isAdd) {
                        await db.models['invoiceInfoYs'].destroy({
                            where: {
                                iid: invoice.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = invoice.id
                        invoiceInfos[i].billNo = invoice.billNo
                        invoiceInfos[i].buId = invoice.buId
                    }
                    await db.models['invoiceInfoYs'].bulkCreate(invoiceInfos, {transaction: t})
                }
                    break
                case 153401:
                case 153402:
                case 153406:
                case 153407: {
                    if(!isAdd) {
                        await db.models['invoiceOther'].destroy({
                            where: {
                                iid: invoice.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = invoice.id
                        invoiceInfos[i].billNo = invoice.billNo
                        invoiceInfos[i].buId = invoice.buId
                    }
                    await db.models['invoiceOther'].bulkCreate(invoiceInfos, {transaction: t})
                } break
                case 153404:
                case 153405: {
                    if(!isAdd) {
                        await db.models['invoiceYsf'].destroy({
                            where: {
                                iid: invoice.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = invoice.id
                        invoiceInfos[i].billNo = invoice.billNo
                        invoiceInfos[i].tenantId = invoice.tenantId
                    }
                    await db.models['invoiceYsf'].bulkCreate(invoiceInfos, {transaction: t})
                } break
                case 160001: {
                    if(!isAdd) {
                        await db.models['invoiceTrans'].destroy({
                            where: {
                                iid: invoice.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = invoice.id
                        invoiceInfos[i].billNo = invoice.billNo
                        invoiceInfos[i].tenantId = invoice.tenantId
                    }
                    await db.models['invoiceTrans'].bulkCreate(invoiceInfos, {transaction: t})
                } break
            }
            // 写入库存余额明细
            await insertInventory(ctx, invoice.id, t)
            // 保存日志
            await saveLogInvoice(tenantId, uid, invoice.id, op, invoice);
        })
        return ctx.suc("保存成功", invoice);
    }
    catch (e) {
        console.log('票据保存失败', e)
        return ctx.err(e)
    }
}

router.post('/bill/billPrintSuc', async ctx => {
    let tenantId = ctx.user.tenantId;
    let cargoId = ctx.request.body.cargoId;
    let cargo = await db.models['cargo'].findOne({
        where: {
            id: cargoId,
            tenantId
        }
    })
    let no = cargo.printNo ? cargo.printNo : 0;
    cargoId.printNo = no
    await cargo.save()
    return ctx.suc('');
})
router.post('/bill/priceHist', async ctx => {
    try {
        let invId = ctx.request.body.invId;
        let buId = ctx.request.body.buId;
        let transType = ctx.request.body.transType;
        let tenantId = ctx.user.tenantId;
        let jsonObject = {};
        if (transType === 150806) {
            let zq = await db.models['zq'].findOne({
                where: {
                    tenantId: tenantId, isCurrent: 1
                }
            })
            let goodsCost = await db.models['goodsCost'].findOne({
                tenantId: tenantId,
                invId: invId,
                zqId: zq.id,
            })
            jsonObject.price = goodsCost.cost;
            if (!goodsCost.cost) {
                let data = await db.models['goods'].findOne({
                    where:{id: invId}
                })
                jsonObject.price = data.price1;
            }
            return ctx.suc('', jsonObject)
        }
        let sql = `select top 1 a.tenantId,a.buId,a.transType,b.invId,b.unit,b.price,b.deduction,b.locationId,b.iid from invoice a 
                    inner join invoice_info b on a.id=b.iid where a.buId=${buId} and a.transType=${transType} and b.invId=${invId} and a.tenantId=${tenantId} and b.price <> 0 order by b.id desc 
                    `;
        let priceHis = await db.query(sql, {type: QueryTypes.SELECT});
        if (priceHis.length === 0) {
            let data = db.models['goods'].findOne({
                where: {
                    id: invId
                }
            })
            if (transType == 150501 || transType == 150502) {
                jsonObject.price = data.price1;
            }
            if (transType == 150601 || transType == 150602 || transType == 150603) {
                jsonObject.price = data.price2;
            }
            return ctx.suc('', jsonObject);
        }
        ctx.suc('', priceHis[0])
    } catch (error) {
        ctx.err(error)
    }
})
//打印成功
router.post('/bill/printSuc', async ctx => {
    let taskId = ctx.request.body.taskId;
    let t = tool.getTime()
    if (taskId) {
        try {
            db.query(`update print_record set stat=1,printAt='${t}' where taskId='${taskId}'`, {type: QueryTypes.UPDATE});
            db.query(`update invoice set printNo=isnull(printNo,0)+1 where id in (select iid from print_record where taskId='${taskId}')`, {type: QueryTypes.UPDATE});
        }
        catch (e) {

        }
    }
    return ctx.suc('');
})
// 返回打印数据
// router.post('/bill/getPrint', async ctx => {
//     let user  = ctx.user
//     let body  = ctx.request.body
//     let tenantId = user.tenantId;
//     let uid = user.id;
//     let roleId = user.roleId;
//     let roleName = user.roleName;
//     if (!roleName) {
//         return ctx.err('还没有设置用户的角色');
//     }
//     if (!roleId) {
//         return ctx.err('还没有设置用户的角色');
//     }
//     let isCard = body.isCard ? body.isCard : false;
//     let showPreview = body.direct ? "PRINT" : "PREVIEW";
//     let ids = body.ids;
//     if(ids.length == 0) return  ctx.err("请选择单据");
//     if(ids.length > 50) return  ctx.err("最大支持 30 张单据批量打印");
//     let op = await getOptionsByName(tenantId,  'system')
//     let options = JSON.parse(op.value)
//     let printHead = user.printHead ? user.printHead : options.printHead
//     if(!printHead) return ctx.err('还没有设置打印抬头,请在设置->系统参数中设置')
//     let descript = options.descript?options.descript:''
//     if (!options.width) {
//         return ctx.err("还未设置打印纸张宽度");
//     }
//     if (!options.height) {
//         return ctx.err("还未设置打印纸张高度");
//     }
//     let  width = parseInt(options.width)
//     let  height = parseInt(options.height)
//     if(width == 0 ) return ctx.err("还未设置纸张宽度,请在 设置->系统参数 进行设置");
//     if(height == 0 ) return ctx.err("还未设置纸张高度,请在 设置->系统参数 进行设置");
//     if(!printHead)  return ctx.err("还未设置打印抬头,请在 设置->系统参数 进行设置");
//     //
//     let taskName = "出货单打印";
//     let print_at = tool.getDay('',0,'DAY', 'YYMMDD HH:mm')
//     let taskId = tool.uuid()
//     let evals = []
//     evals.push(`LODOP.PRINT_INIT('${taskName}')`)
//     evals.push({str: "LODOP.SET_PREVIEW_WINDOW(1,2,1,900, 700)"})
//     evals.push({str: `LODOP.SET_PRINT_PAGESIZE(0,${width},${height},'A4')`})
//     let rets = {}
//     // 取主票据
//     if (!isCard) {
//         let orders = await db.models['invoice'].findAll({
//             where: {
//                 tenantId,
//                 id: {
//                     [Op.in]: ids
//                 }
//             }
//         })
//         // 打印记录
//         let printRecords = []
//         for (let i = 0; i < orders.length; i++) {
//             let item = orders[i]
//             let print = await assamblePrint(print_at, item, printHead, descript, ctx);
//             if(!print.stat) return print
//             let printNo = tool.xe.toNumber(item.printNo) + 1;
//             // // 打印记录
//             // PrintRecord printRecord = new PrintRecord();
//             // printRecord.setTenantId(item.getTenantId());
//             // printRecord.setIid(item.getId());
//             // printRecord.setTaskId(taskId);
//             // printRecord.setPrintBy(uid);
//             // printRecord.setPrintNo(printNo);
//             // printRecord.setStat(0);
//             // printRecord.setPrintData(print);
//             // printRecords.add(printRecord);
//             //
//             evals.push({str: `LODOP.ADD_PRINT_BARCODE(10,550,90,90,'QRCode', '${item.transType}-${item.id}) + "')`});
//             evals.push({str: '', data: print.data})
//             if (orders.length > 1)  evals.push({str: 'LODOP.NewPageA()'});
//         }
//         evals.push({str: `LODOP.${showPreview}()`})

//         // iPrintRecordService.saveBatch(printRecords);
//         //
//         rets.task_id = taskId
//         rets.evals = evals
//     }
//     // if (isCard) {
//     //     QueryWrapper<Card> queryWrapper = new QueryWrapper<>();
//     //     queryWrapper.in("id", ids);
//     //     List<Card> cards = iCardService.list(queryWrapper);
//     //     List<JSONObject> userInfo = selectList("select * from admin where tenantId=" + tenantId);
//     //     // 打印记录
//     //     List<PrintRecord> printRecords= new ArrayList<>();
//     //     for (Card card : cards) {
//     //         QueryWrapper<CardInfo> queryWrapper1 = new QueryWrapper<>();
//     //         queryWrapper1.eq("cardId", card.getId());
//     //         List<CardInfo> cardInfos = iCardInfoService.list(queryWrapper1);
//     //         int printNo = card.getPrintNo() + 1;
//     //         StringBuilder head = new StringBuilder();
//     //         head.push("<table cellpadding='0' cellspacing='0' style='border-collapse: collapse;width: 100%;' >");
//     //         head.push("<thead>");
//     //         head.push("<tr><th style='text-align: center;height: 40px' colspan='8'><span style='font-size: 22px'>");
//     //         head.push(printHead).push(" 记账凭证");
//     //         head.push("</span><div style='text-align: left;position: absolute;left: 3px;top:10px;font-size: 12px;font-weight: normal'>");
//     //         head.push(" <div>票号：").push(card.getBillNo()).push("</div><div>日期：").push(card.getBillDate()).push("</div></div>" +
//     //             "<div style='text-align: right;position: absolute;right: 10px;top:3px;font-size: 12px;font-weight: normal'><span tdata='PageNO'>##</span>" +
//     //             "<span>/</span><span tdata='PageCount'>##</span>页 <span></span> " + print_at + "-<span>" + printNo + "</span></div>"+
//     //             "</th></tr>");
//     //         //
//     //         head.push("<tr><td colspan='5' style='font-size: 14px'>");
//     //         head.push("<div><span>搞要：").push(card.getRemark()).push("</span> </div></td></tr>");
//     //         //
//     //         head.push("<tr>");
//     //         head.push("   <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 130px;text-align: center;padding: 2px;'>摘要</td>");
//     //         head.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 120px;text-align: center;padding: 2px;'>会计科目</td>");
//     //         head.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 100px;text-align: center;padding: 2px;'>借方金额</td>");
//     //         head.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width: 100px;text-align: center;padding: 2px;'>贷方金额</td>");
//     //         head.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: center;padding: 2px;'>往来单位</td>");
//     //         head.push("</tr></thead><tbody>");
//     //         //
//     //         for (CardInfo cardInfo : cardInfos) {
//     //             BigDecimal price1 = cardInfo.getPrice1() == null ? BigDecimal.ZERO : cardInfo.getPrice1();
//     //             BigDecimal price2 = cardInfo.getPrice2() == null ? BigDecimal.ZERO : cardInfo.getPrice2();
//     //             head.push("<tr><td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black;width:120px; text-align: left;padding: 2px;font-size:12px;'>").push(cardInfo.getRemark()).push("</td>");
//     //             head.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: left;padding: 2px;'>").push(cardInfo.getSubjectName()).push("</td>");
//     //             head.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: right;padding: 2px;'>").push(price1.compareTo(BigDecimal.ZERO) == 0 ? "" : price1).push("</td>");
//     //             head.push("    <td style='border-left: 1px solid black;border-right: 1px solid black;border-top: 1px solid black; text-align: right;padding: 2px;'>").push(price2.compareTo(BigDecimal.ZERO) == 0 ? "" : price2).push("</td>");
//     //             head.push("    <td style='border-left : 1px solid black;border-right: 1px solid black;border-top: 1px solid black;text-align: left;padding: 2px;font-size:12px;'>").push(cardInfo.getBuName()).push("</td></tr>");
//     //         }
//     //         head.push( " </tbody><tfoot> ");
//     //
//     //         String userName = "";
//     //         for(JSONObject jsonObject : userInfo) {
//     //             if (jsonObject.getInteger("id").equals(card.getCby())) {
//     //                 userName = jsonObject.getString("name");
//     //             }
//     //         }
//     //         //
//     //         head.push( "<tr><td colspan='5' style='border: 1px solid black;' ></td></tr>" +
//     //             "<tr>" +
//     //             "<td colspan='2' style='border: 1px solid black;text-align: left;padding:2px 2px 2px 0; ' >合计：</td>"+
//     //             "<td tindex='3' tdata='AllSum' format='0.00'  style='border: 1px solid black;text-align: right;padding-right: 2px' >########</td>" +
//     //             "<td tindex='4' tdata='AllSum' format='0.00'  style='border: 1px solid black;text-align: right;padding-right: 2px' >########</td>"+
//     //             "<td style='border: 1px solid black'></td>" +
//     //             "</tr>");
//     //         head.push("<tr><td colspan='5' > 制单人:").push(userName).push(" </td> </tr></tfoot></table>");
//     //
//     //
//     //         String print =  head.toString();
//     //         // 打印记录
//     //         PrintRecord printRecord = new PrintRecord();
//     //         printRecord.setTenantId(card.getTenantId());
//     //         printRecord.setIid(card.getId());
//     //         printRecord.setTaskId(taskId);
//     //         printRecord.setPrintBy(uid);
//     //         printRecord.setPrintNo(printNo);
//     //         printRecord.setStat(0);
//     //         printRecord.setPrintData(print);
//     //         printRecords.add(printRecord);
//     //
//     //         evals.add(new HashMap<>(1){{ put("str", "LODOP.ADD_PRINT_BARCODE(10,550,90,90,'QRCode', 'PZ-" + card.getId().toString() + "')"); }});
//     //         evals.add(new HashMap<>(2){{ put("str", ""); put("data", print); }});
//     //         if (cards.size() > 1)  evals.add(new HashMap<>(1){{ put("str", "LODOP.NewPageA()"); }});
//     //     }
//     //     evals.add(new HashMap<>(1){{ put("str", "LODOP." + showPreview + "()"); }});
//     //
//     //     iPrintRecordService.saveBatch(printRecords);
//     //     //
//     //     rets.put("task_id", taskId);
//     //     rets.put("evals", evals);
//     // }
//     //
//     // return  rets;

//     return ctx.suc('', rets);
// })
// 保存票据
router.post('/bill/save', async ctx => {
    return  await saveInvoiceData(ctx)
})
// 手机确认收款
router.post('/bill/saveSkBill', async ctx => {
    return  await saveInvoiceData(ctx)
})
// 记账
router.post('/bill/toAccounted', async ctx => {
    let body = ctx.request.body
    let ter = body.ter
    let isScan = body.byScan ? 1: 0
    let menuId = body.menuId
    let ids = body.ids
    let byCell = ter === 'app' ? 1 : 0;
    // 检查权限
    // if (isScan == 0) {
    //     if(menuId !=0) doCheckAuth(roleId, roleName, menuId, "accounted");
    // }
    // 记账
    try {
        await toAccounted(ctx);
        return ctx.suc("【已记账】 " + ids.length);
    }
    catch (e) {
        console.log('记账失败', e)
        return ctx.err(e)
    }
})
// 作废
router.post('/bill/toWasted', async ctx => {
    let id = ctx.request.body.ids[0];
    let infos = await db.models['invoiceInfo'].findAll({
        where: {
            iid: id
        }
    })
    let uid = ctx.user.id
    let tenantId = ctx.user.tenantId
    let invoice = await db.models['invoice'].findByPk(id)
    let transType = invoice.transType
    ctx.request.body.transType = transType
    ctx.request.body.invoiceInfos = infos
    await detectStock(ctx)
    if(invoice.billState !== 'accounted') return ctx.err('未记账票据')
    if(transType === 153403) {
        let sqls = `select count(*) num from invoice a inner join  invoice_info b on a.id=b.iid and a.billState<>'del' and a.tenantId=${tenantId}  
                    where b.ysId in (select id from invoice_info_ys where id=${id})`;
        let used = await db.query(sqls, {type: QueryTypes.SELECT, plain: true})
        if(used) {
            return  ctx.err('已使用, 不能退审')
        }
    }
    // 是否有收付款记录
    await detectHasReceipt(ctx.user.tenantId, id);
    if(invoice.isInit) return ctx.err('不能退审期初数据')
    await billCanEdit(invoice.billDate, tenantId);
    invoice.billState = 'draft'
    invoice.wastedAt = tool.getTime()
    invoice.wastedBy = ctx.user.id
    invoice.updatedAt = tool.getTime()
    // 退审票据主表
    invoice.accountedAt = null;
    invoice.accountedBy = null
    await db.transaction(async  t => {
        await invoice.save({transaction: t})
        // 更新库存
        if ([150601,150602,150603,150501,150502,150706,150806].indexOf(transType) !== -1 ) {
            await db.models['invoiceInfo'].update({
                billState: 'draft'
            }, {
                where: {
                    iid: invoice.id
                }
            }, {transaction: t})
            await db.models['inventoryDetail'].update({
                isCal: 0
            }, {
                where: {
                    iid: invoice.id
                }
            }, {transaction: t})
            await updateInventoryByBill(ctx, invoice.id, t)
        }
        await saveLogInvoice(tenantId, uid, invoice.id, "退审", invoice, t);

    })
    return ctx.suc('已退审')
})
// 删除
router.post('/bill/toDel', async ctx => {
    let body = ctx.request.body
    let ids = body.ids
    await db.transaction(async t => {
        for (let i = 0; i < ids.length; i++) {
            let invoice = await db.models['invoice'].findOne({
                where: {
                    id: ids[i],
                    tenantId: ctx.user.tenantId,
                    billState: 'draft',
                    isDelete: 0
                }
            })
            if (!invoice)  ctx.err("不能删除该状态的票据");
            invoice.isDelete = 1
            invoice.billState = 'del'
            invoice.deletedBy = ctx.user.id
            invoice.deletedAt = tool.getTime()
            await invoice.save({transaction: t})
            if ([150601,150602,150603,150501,150502,150706,150806].indexOf(transType) !== -1 ) {
                await db.models['invoiceInfo'].update({
                    billState: 'del'
                }, {
                    where: {
                        iid: invoice.id
                    }
                }, {transaction: t})
            }

            await saveLogInvoice(ctx.user.tenantId, ctx.user.id, invoice.id, "删除", invoice, t);
        }
    })
    return ctx.suc("已删除 " + ids.length );


})
// 票据应收金额查询,扫码查询应收票据
router.post('/bill/getYsById', async ctx => {
    let body = ctx.request.body
    let tenantId = ctx.user.tenantId
    let id = body.id
    let sql = `
        select * from (
                          select a.id,a.billNo,a.billDate,a.transTypeName,a.buId,c.name buName,a.billState,a.arrears,b.hxAmount,a.id billId,
                                 a.billNo srcBillNo,a.billType srcBillType,a.transTypeName srcTransTypeName,a.transType srcTransType,a.tenantId,
                                 (a.arrears-isnull(b.hxAmount,0)) leftAmount,
                                 (a.arrears-isnull(b.hxAmount,0)) nowCheck, 0 yhAmount  from
                              (
                                  SELECT * from invoice where id=${id} and tenantId=${tenantId}
                              ) a
                                  left join
                              (
                                  SELECT a.billId,sum(isnull(a.nowCheck,0)+ISNULL(a.yhAmount, 0)) hxAmount 
                                  FROM invoice_receipt a inner join invoice b on a.iid=b.id where a.billId=${id}  
                                  and b.tenantId=${tenantId} and b.billState <> 'del' GROUP BY a.billId
                              ) b on a.id=b.billId
                                  left join contact c on a.buId=c.id
                      ) a 
    `
    let ret = await db.query(sql, {type: QueryTypes.SELECT, plain: true})
    if(!ret) {
        return ctx.err('未找到相应票据')
    }
    if(ret.billState === 'del') {
        return ctx.err('该票据已被删除,不能收款')
    }
    if(ret.billState === 'draft') {
        return ctx.err('草稿数据，要先审核后才能收款')
    }
    if(tool.xe.toNumber(ret.leftAmount) === 0) return ctx.err('该票据已收完款')
    return ctx.suc('', ret)
})
// 查询收款票据
router.post('/bill/getSkBill', async ctx => {
    let body = ctx.request.body
    let tenantId = ctx.user.tenantId
    let currentPage = body.currentPage
    let pageSize = 20
    let skip = (currentPage - 1) * pageSize
    let uid = ctx.user.id
    let formData = body.formData
    let sql = `
        select a.id,
               a.tenantId,
               a.billNo,
               a.billDate,
               a.transType,
               a.transTypeName,
               a.buId,
               a.billState,
               a.billType,
               case when a.transType = 150602 then -a.arrears else a.arrears end arrears,
               b.name buName from invoice a 
                   inner join contact b on a.buId=b.id and a.tenantId=${tenantId} and a.billType='SALE' and a.billState='accounted' 
    `
    if(formData.mybill) {
        sql += ` and a.salesId=${uid} `
    }
    if(formData.buName) {
        sql += ` and b.name like '%${formData.buName}%' `
    }
    if(formData.endDate) {
        sql += ` and a.billDate<='${formData.endDate}' `
    }
    let receipt = `
        SELECT a.billId,sum(isnull(a.nowCheck,0)+ISNULL(a.yhAmount, 0)) hxAmount FROM 
        invoice_receipt a inner join invoice b on a.iid=b.id where a.tenantId=${tenantId} and b.billState='accounted'  GROUP BY a.billId
    `
    let retsql = `
        select a.id,a.billNo,a.billDate,a.transTypeName,a.buId,a.buName,a.billState,a.arrears,b.hxAmount,a.id billId,
                                 a.billNo srcBillNo,a.billType srcBillType,a.transTypeName srcTransTypeName,a.transType srcTransType,a.tenantId,
                                 (a.arrears-isnull(b.hxAmount,0)) leftAmount,(a.arrears-isnull(b.hxAmount,0)) nowCheck, 0 yhAmount  from
                              (${sql}) a left join (${receipt}) b on a.id=b.billId
    `
    let lastSql = `
        select * from ( ${retsql} )  a where leftAmount<>0 order by a.buId, billDate asc offset ${skip} row fetch next ${pageSize} rows only;
    `

    let totalsql = `select count(*) total from (${retsql}) a where leftAmount<>0 `
    let total = await db.query(totalsql, {type: QueryTypes.SELECT, plain: true})
    let ret = await db.query(lastSql, {type: QueryTypes.SELECT})
    return ctx.suc('', {
        total: total.total,
        list: ret
    })
})
// 交款核对
router.post('/bill/getTodaySk', async ctx => {
    let body = ctx.request.body
    let tid = ctx.user.tenantId
    let billDate = body.billDate
    let uid = body.uid
    let sql = `
        SELECT a.*, b.name accName
        from (SELECT accId, sum(accAmount) amount
              from (SELECT a.accId, sum(isnull(a.accAmount, 0)) accAmount
                    from invoice a
                    where a.tenantId = ${tid}
                      and a.billType = 'RECEIPT'
                      and a.cby = ${uid}
                      and a.doId = ${uid}
                      and a.billState = 'draft'
                      and a.billDate = '${billDate}'
                      and isnull(accId, 0) <> 0
                    GROUP BY accId
                    union all
                    SELECT a.accId1 accId, sum(isnull(a.accAmount1, 0)) accAmount
                    from invoice a
                    where a.tenantId = ${tid}
                      and a.billType = 'RECEIPT'
                      and a.cby = ${uid}
                      and a.doId = ${uid}
                      and a.billState = 'draft'
                      and a.billDate = '${billDate}'
                      and isnull(accId1, 0) <> 0
                    GROUP BY accId1) a
              GROUP BY accId) a
                 left join category b on a.accId = b.id
     `
    let acc = await db.query(sql, {type: QueryTypes.SELECT})
    let ss = 0 // 实收
    acc.map(row => {
        row.amount = tool.xe.toFixed(row.amount, 2)
        ss = tool.xe.add(row.amount, ss)
    })
    // 商户数量
    let shsql = `
        select count(*) total
        from (SELECT buId
              from invoice a
              where a.tenantId = ${tid}
                and a.billType = 'RECEIPT'
                and a.cby = ${uid}
                and a.doId = ${uid}
                and a.billState='draft'
                and a.billDate = '${billDate}'
              GROUP BY buId) a
    `
    let shs = await db.query(shsql, {type: QueryTypes.SELECT, plain: true})
    let pjsql = `
        SELECT count(*) total 
        from 
        (
         SELECT billId from 
         (
         SELECT a.id from invoice a where 
           a.tenantId=${tid} and a.billType='RECEIPT' and a.cby=${uid} and a.doId=${uid} and a.billState='draft' and a.billDate='${billDate}'
         ) a inner join invoice_receipt b on a.id=b.iid GROUP BY billId
         ) a 
    `
    let pjs = await db.query(pjsql, {type: QueryTypes.SELECT, plain: true})
    let yhsql = `
     SELECT sum(isnull(yhAmount,0)) total from invoice a where 
    a.tenantId=${tid} and a.billType='RECEIPT' and a.cby=${uid}  and a.doId=${uid}  and a.billState='draft'  and a.billDate='${billDate}'
    `
    // 优惠合计
    let yh = await db.query(yhsql, {type: QueryTypes.SELECT, plain: true})
    // 本次合计
    let bcsql = `
        SELECT sum(totalAmount) total from invoice a where 
        a.tenantId=${tid} and a.billType='RECEIPT' and a.cby=${uid} and a.doId=${uid} and a.billState='draft'  and a.billDate='${billDate}'
    `
    let bc = await db.query(bcsql, {type: QueryTypes.SELECT, plain: true})
    let yssql = `
      SELECT sum(isnull(b.leftAmount,0)) total from invoice a inner join invoice_receipt b on a.id=b.iid where 
        a.tenantId=${tid} and a.billType='RECEIPT' and a.cby=${uid} and a.doId=${uid} and a.billState='draft'  and a.billDate='${billDate}'
    `
    let ys = await db.query(yssql, {type: QueryTypes.SELECT, plain: true})
    return ctx.suc('', {
        accList: acc,
        ss: tool.xe.toFixed(ss, 2),
        shs: shs ? shs.total : '',
        pjs: pjs ? pjs.total : '',
        yh: yh ? tool.xe.toFixed(yh.total, 2) : '',
        bc: bc ? tool.xe.toFixed(bc.total, 2) : '',
        ys: bc ? tool.xe.toFixed(ys.total, 2) : '',
    })

})
// 收款的业务票据及收款票据,电脑 交款核对页面
router.post('/bill/getSkBills', async ctx => {
    let body = ctx.request.body
    let tid = ctx.user.tenantId
    let billDate = body.billDate
    let uid = body.uid
    let sksql = `
    SELECT a.billDate,a.id,a.transType,a.transTypeName,a.amount,a.billNo, 
           case when a.billState='draft' then '草稿' when a.billState='accounted' then '已记账' end billState 
           from invoice a where  a.jkState='待审核' and 
           a.tenantId=${tid} and a.billType='RECEIPT' and a.cby=${uid} and a.doId=${uid} and a.billState='accounted'  and a.billDate='${billDate}'
    `
    let skBills = await db.query(sksql, {type: QueryTypes.SELECT})
    let bizsql = `
    SELECT a.billDate,a.id,a.transType,a.transTypeName,a.amount,a.billNo,
           case when a.billState='draft' then '草稿' when a.billState='accounted' then '已记账' end billState 
    from 
        (
        SELECT b.billId from invoice a inner join invoice_receipt b on a.id=b.iid and 
                   a.tenantId=${tid} and a.billType='RECEIPT' and a.cby=${uid} and a.doId=${uid} and a.billState='accounted' and a.billDate='${billDate}' 
                        and a.jkState='待审核'
        ) b inner join invoice a on b.billId=a.id
    `
    let bizBills = await db.query(bizsql, {type: QueryTypes.SELECT})
    return ctx.suc('', {
        skList: skBills,
        bizList: bizBills
    })
})
// 确认领取收款单据
router.post('/bill/confirmGetReceipt', async ctx => {
    let tid = ctx.user.tenantId
    let details = ctx.request.body
    let appdetails = []
    for (let i = 0; i < details.length; i++) {
        appdetails.push({
            tenantId: tid,
            billState: '收款中',
            doId: details[i].doId,
            iid: details[i].id,
            buId: details[i].buId,
            buName: details[i].buName,
            salesBillDate: details[i].billDate,
            salesBillNo: details[i].billNo,
            salesId: details[i].salesId,
            salesName: details[i].salesName,
            arrears: details[i].arrears,
            leftAmount: details[i].leftAmount,
            billDate: tool.getDay(),
            cby: ctx.user.id,
            ctime: tool.getTime()
        })
    }
    await db.models['appSk'].bulkCreate(appdetails)
    return ctx.suc('领单成功')
})

module.exports = router;
